package payfun

import (
	"context"
	"errors"
	"fmt"
	"strconv"
	"time"

	"gitee.com/liuxuezhan/ar-platform/admin-api/internal/pay/base"
	"gitee.com/liuxuezhan/ar-platform/admin-api/pkg/xerrors/assets"
	"github.com/bytedance/sonic/decoder"
)

type Factory struct {
}

func (p *Factory) CreatePay(config base.Config) base.Payment {
	return &Bcpay{
		Url:       config.Url,
		AppId:     config.AppId,
		SecretKey: config.SecretKey,
		ReturnUrl: config.ReturnUrl,
		NotifyUrl: config.NotifyUrl,
	}
}

type Bcpay struct {
	AppId     string
	SecretKey string
	Url       string
	ReturnUrl string
	NotifyUrl string
}

type Resp struct {
	Code int64  `json:"code"`
	Msg  string `json:"msg"`
	Data any    `json:"data"`
}

// 代收订单创建
func (bc *Bcpay) Withdraw(ctx context.Context, req map[string]any) (resp base.WithdrawRes, err error) {
	// 请求第三方接口
	url := bc.Url + "/inr/payment"
	params := make(map[string]any)
	params["appKey"] = bc.AppId
	params["orderId"] = req["Order"].(map[string]any)["OrderNo"]
	params["amount"] = fmt.Sprintf("%.2f", req["Order"].(map[string]any)["RealAmount"])
	params["callbackUrl"] = bc.NotifyUrl
	params["account"] = req["Order"].(map[string]any)["UserBank"].(map[string]any)["CardNumber"]
	params["personName"] = req["Order"].(map[string]any)["UserBank"].(map[string]any)["UserName"]
	params["ifsc"] = req["Order"].(map[string]any)["UserBank"].(map[string]any)["IfscCode"]
	params["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
	if nonce, err := UniqueRandomString(16); err != nil {
		return resp, err
	} else {
		params["nonce"] = nonce
	}
	if v, err := GenerateSignature(params, bc.SecretKey); err != nil {
		return resp, assets.ErrSignGenerateFailed
	} else {
		params["sign"] = v
	}
	result, err := sendRequest(ctx, url, params, "post")
	if err != nil {
		return
	}
	resp = base.WithdrawRes{
		OrderSn: result.Data.(map[string]any)["orderId"].(string),
	}
	return
}

// 发送请求
func sendRequest(ctx context.Context, url string, params map[string]any, method string) (resp Resp, err error) {
	output, err := base.SendJson(ctx, url, params, method)
	if err != nil {
		return resp, err
	}
	dc := decoder.NewDecoder(output)
	dc.UseNumber()
	dc.Decode(&resp)
	if resp.Code != 1 {
		return resp, errors.New(resp.Msg)
	}
	return
}
